Libérez la puissance de WebCodecs ! Un guide complet pour accéder et manipuler les données des trames vidéo via les plans VideoFrame. Découvrez les formats de pixels, l'organisation en mémoire et les cas d'usage pour le traitement vidéo avancé dans le navigateur.
Plan VideoFrame de WebCodecs : Exploration approfondie de l'accès aux données des trames vidéo
WebCodecs représente un changement de paradigme dans le traitement multimédia sur le web. Il fournit un accès de bas niveau aux composants fondamentaux des médias, permettant aux développeurs de créer des applications sophistiquées directement dans le navigateur. L'une des fonctionnalités les plus puissantes de WebCodecs est l'objet VideoFrame, et à l'intérieur de celui-ci, les plans VideoFrame qui exposent les données brutes des pixels des trames vidéo. Cet article offre un guide complet pour comprendre et utiliser les plans VideoFrame pour la manipulation vidéo avancée.
Comprendre l'objet VideoFrame
Avant de plonger dans les plans, rappelons ce qu'est l'objet VideoFrame lui-même. Un VideoFrame représente une seule trame de vidéo. Il encapsule les données vidéo décodées (ou encodées), ainsi que les métadonnées associées comme l'horodatage, la durée et les informations de format. L'API VideoFrame offre des méthodes pour :
- Lire les données des pixels : C'est là que les plans entrent en jeu.
- Copier des trames : Créer de nouveaux objets
VideoFrameà partir de ceux existants. - Fermer des trames : Libérer les ressources sous-jacentes détenues par la trame.
L'objet VideoFrame est créé durant le processus de décodage, typiquement par un VideoDecoder, ou manuellement lors de la création d'une trame personnalisée.
Que sont les plans VideoFrame ?
Les données de pixels d'un VideoFrame sont souvent organisées en plusieurs plans, surtout dans des formats comme le YUV. Chaque plan représente une composante différente de l'image. Par exemple, dans un format YUV420, il y a trois plans :
- Y (Luma) : Représente la luminosité (luminance) de l'image. Ce plan contient l'information en niveaux de gris.
- U (Cb) : Représente la composante de chrominance différence-bleu.
- V (Cr) : Représente la composante de chrominance différence-rouge.
Les formats RGB, bien qu'apparemment plus simples, peuvent aussi utiliser plusieurs plans dans certains cas. Le nombre de plans et leur signification dépendent entièrement du VideoPixelFormat du VideoFrame.
L'avantage d'utiliser des plans est que cela permet un accès et une manipulation efficaces des composantes de couleur spécifiques. Par exemple, vous pourriez vouloir ajuster uniquement la luminance (plan Y) sans affecter la couleur (plans U et V).
Accéder aux plans VideoFrame : L'API
L'API VideoFrame fournit les méthodes suivantes pour accéder aux données des plans :
copyTo(destination, options): Copie le contenu duVideoFramevers une destination, qui peut être un autreVideoFrame, unCanvasImageBitmap, ou uneArrayBufferView. L'objetoptionscontrôle quels plans sont copiés et comment. C'est le mécanisme principal pour l'accès aux plans.
L'objet options dans la méthode copyTo vous permet de spécifier la disposition et la cible pour les données de la trame vidéo. Les propriétés clés incluent :
format: Le format de pixel souhaité pour les données copiées. Il peut être le même que celui duVideoFrameoriginal ou un format différent (par exemple, convertir de YUV à RGB).codedWidthetcodedHeight: La largeur et la hauteur de la trame vidéo en pixels.layout: Un tableau d'objets décrivant la disposition de chaque plan en mémoire. Chaque objet du tableau spécifie :offset: Le décalage, en octets, depuis le début du tampon de données jusqu'au début des données du plan.stride: Le nombre d'octets entre le début de chaque ligne dans le plan. C'est crucial pour gérer le remplissage (padding).
Voyons un exemple de copie d'un VideoFrame YUV420 vers un tampon brut :
async function copyYUV420ToBuffer(videoFrame, buffer) {
const width = videoFrame.codedWidth;
const height = videoFrame.codedHeight;
// YUV420 a 3 plans : Y, U, et V
const yPlaneSize = width * height;
const uvPlaneSize = width * height / 4;
const layout = [
{ offset: 0, stride: width }, // Plan Y
{ offset: yPlaneSize, stride: width / 2 }, // Plan U
{ offset: yPlaneSize + uvPlaneSize, stride: width / 2 } // Plan V
];
await videoFrame.copyTo(buffer, {
format: 'I420',
codedWidth: width,
codedHeight: height,
layout: layout
});
videoFrame.close(); // Important pour libérer les ressources
}
Explication :
- Nous calculons la taille de chaque plan en fonction de la
widthet de laheight. Y est en pleine résolution, tandis que U et V sont sous-échantillonnés (4:2:0). - Le tableau
layoutdéfinit l'organisation en mémoire. L'offsetspécifie où chaque plan commence dans le tampon, et lestridespécifie le nombre d'octets à sauter pour passer à la ligne suivante dans ce plan. - L'option
formatest définie sur 'I420', qui est un format YUV420 courant. - Point crucial, après la copie,
videoFrame.close()est appelée pour libérer les ressources.
Formats de pixels : Un monde de possibilités
Comprendre les formats de pixels est essentiel pour travailler avec les plans VideoFrame. Le VideoPixelFormat définit comment l'information de couleur est encodée dans la trame vidéo. Voici quelques formats de pixels courants que vous pourriez rencontrer :
- I420 (YUV420p) : Un format YUV planaire où les composantes Y, U et V sont stockées dans des plans séparés. U et V sont sous-échantillonnés d'un facteur 2 dans les dimensions horizontale et verticale. C'est un format très courant et efficace.
- NV12 (YUV420sp) : Un format YUV semi-planaire où Y est stocké dans un plan, et les composantes U et V sont entrelacées dans un second plan.
- RGBA : Les composantes Rouge, Vert, Bleu et Alpha sont stockées dans un seul plan, typiquement avec 8 bits par composante (32 bits par pixel). L'ordre des composantes peut varier (par ex., BGRA).
- RGB565 : Les composantes Rouge, Vert et Bleu sont stockées dans un seul plan avec 5 bits pour le Rouge, 6 bits pour le Vert et 5 bits pour le Bleu (16 bits par pixel).
- GRAYSCALE : Représente les images en niveaux de gris avec une seule valeur de luma (luminosité) pour chaque pixel.
La propriété VideoFrame.format vous indiquera le format de pixel d'une trame donnée. Assurez-vous de vérifier cette propriété avant de tenter d'accéder aux plans. Vous pouvez consulter la spécification WebCodecs pour une liste complète des formats pris en charge.
Cas d'utilisation pratiques
L'accès aux plans VideoFrame ouvre un large éventail de possibilités pour le traitement vidéo avancé dans le navigateur. Voici quelques exemples :
1. Effets vidéo en temps réel
Vous pouvez appliquer des effets vidéo en temps réel en manipulant les données de pixels dans le VideoFrame. Par exemple, vous pourriez implémenter un filtre de niveaux de gris en faisant la moyenne des composantes R, G et B de chaque pixel dans une trame RGBA, puis en attribuant cette valeur moyenne aux trois composantes. Vous pourriez également créer un effet de ton sépia ou ajuster la luminosité et le contraste.
async function applyGrayscale(videoFrame) {
const width = videoFrame.codedWidth;
const height = videoFrame.codedHeight;
const buffer = new ArrayBuffer(width * height * 4); // RGBA
const rgba = new Uint8ClampedArray(buffer);
await videoFrame.copyTo(rgba, {
format: 'RGBA',
codedWidth: width,
codedHeight: height
});
for (let i = 0; i < rgba.length; i += 4) {
const r = rgba[i];
const g = rgba[i + 1];
const b = rgba[i + 2];
const gray = (r + g + b) / 3;
rgba[i] = gray; // Rouge
rgba[i + 1] = gray; // Vert
rgba[i + 2] = gray; // Bleu
}
// Créer un nouveau VideoFrame à partir des données modifiées.
const newFrame = new VideoFrame(rgba, {
format: 'RGBA',
codedWidth: width,
codedHeight: height,
timestamp: videoFrame.timestamp,
duration: videoFrame.duration
});
videoFrame.close(); // Libérer la trame originale
return newFrame;
}
2. Applications de vision par ordinateur
Les plans VideoFrame fournissent un accès direct aux données de pixels nécessaires pour les tâches de vision par ordinateur. Vous pouvez utiliser ces données pour implémenter des algorithmes de détection d'objets, de reconnaissance faciale, de suivi de mouvement, et plus encore. Vous pouvez tirer parti de WebAssembly pour les sections de votre code critiques en termes de performance.
Par exemple, vous pourriez convertir un VideoFrame en couleur en niveaux de gris, puis appliquer un algorithme de détection de contours (par ex., opérateur de Sobel) pour identifier les bords dans l'image. Cela pourrait être utilisé comme une étape de pré-traitement pour la reconnaissance d'objets.
3. Montage vidéo et composition
Vous pouvez utiliser les plans VideoFrame pour implémenter des fonctionnalités de montage vidéo comme le recadrage, le redimensionnement, la rotation et la composition. En manipulant directement les données de pixels, vous pouvez créer des transitions et des effets personnalisés.
Par exemple, vous pourriez recadrer un VideoFrame en copiant seulement une partie des données de pixels vers un nouveau VideoFrame. Vous ajusteriez les décalages et les strides du layout en conséquence.
4. Codecs personnalisés et transcodage
Bien que WebCodecs offre un support intégré pour les codecs courants comme AV1, VP9 et H.264, vous pouvez également l'utiliser pour implémenter des codecs personnalisés ou des pipelines de transcodage. Vous devriez gérer le processus d'encodage et de décodage vous-même, mais les plans VideoFrame vous permettent d'accéder et de manipuler les données de pixels brutes. Cela pourrait être utile pour des formats vidéo de niche ou des exigences d'encodage spécialisées.
5. Analyses avancées
En accédant aux données de pixels sous-jacentes, vous pouvez effectuer une analyse approfondie du contenu vidéo. Cela inclut des tâches telles que la mesure de la luminosité moyenne d'une scène, l'identification des couleurs dominantes ou la détection des changements dans le contenu de la scène. Cela peut permettre des applications d'analyse vidéo avancées pour la sécurité, la surveillance ou l'analyse de contenu.
Travailler avec Canvas et WebGL
Bien que vous puissiez manipuler directement les données de pixels dans les plans VideoFrame, vous devez souvent en rendre le résultat à l'écran. L'interface CanvasImageBitmap sert de pont entre VideoFrame et l'élément <canvas>. Vous pouvez créer un CanvasImageBitmap à partir d'un VideoFrame puis le dessiner sur le canevas en utilisant la méthode drawImage().
async function renderVideoFrameToCanvas(videoFrame, canvas) {
const bitmap = await createImageBitmap(videoFrame);
const ctx = canvas.getContext('2d');
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
bitmap.close(); // Libérer les ressources du bitmap
videoFrame.close(); // Libérer les ressources du VideoFrame
}
Pour un rendu plus avancé, vous pouvez utiliser WebGL. Vous pouvez téléverser les données de pixels des plans VideoFrame vers des textures WebGL, puis utiliser des shaders pour appliquer des effets et des transformations. Cela vous permet de tirer parti du GPU pour un traitement vidéo haute performance.
Considérations sur les performances
Travailler avec des données de pixels brutes peut être intensif en calcul, il est donc crucial de considérer l'optimisation des performances. Voici quelques conseils :
- Minimiser les copies : Évitez les copies inutiles de données de pixels. Essayez d'effectuer des opérations sur place autant que possible.
- Utiliser WebAssembly : Pour les sections de votre code critiques en termes de performance, envisagez d'utiliser WebAssembly. WebAssembly peut fournir des performances proches du natif pour les tâches gourmandes en calcul.
- Optimiser l'organisation en mémoire : Choisissez le bon format de pixel et la bonne organisation en mémoire pour votre application. Envisagez d'utiliser des formats compacts (par ex., RGBA) si vous n'avez pas besoin d'accéder fréquemment aux composantes de couleur individuelles.
- Utiliser OffscreenCanvas : Pour le traitement en arrière-plan, utilisez
OffscreenCanvaspour éviter de bloquer le thread principal. - Profiler votre code : Utilisez les outils de développement du navigateur pour profiler votre code et identifier les goulots d'étranglement de performance.
Compatibilité des navigateurs
WebCodecs et l'API VideoFrame sont pris en charge dans la plupart des navigateurs modernes, y compris Chrome, Firefox et Safari. Cependant, le niveau de prise en charge peut varier en fonction de la version du navigateur et du système d'exploitation. Consultez les derniers tableaux de compatibilité des navigateurs sur des sites comme MDN Web Docs pour vous assurer que les fonctionnalités que vous utilisez sont prises en charge dans vos navigateurs cibles. Pour une compatibilité entre navigateurs, la détection de fonctionnalités est recommandée.
Pièges courants et dépannage
Voici quelques pièges courants à éviter lorsque vous travaillez avec les plans VideoFrame :
- Disposition incorrecte : Assurez-vous que le tableau
layoutdécrit avec précision l'organisation en mémoire des données de pixels. Des décalages ou des strides incorrects peuvent entraîner des images corrompues. - Formats de pixels incompatibles : Assurez-vous que le format de pixel que vous spécifiez dans la méthode
copyTocorrespond au format réel duVideoFrame. - Fuites de mémoire : Fermez toujours les objets
VideoFrameetCanvasImageBitmaplorsque vous avez terminé avec eux pour libérer les ressources sous-jacentes. Ne pas le faire peut entraîner des fuites de mémoire. - Opérations asynchrones : N'oubliez pas que
copyToest une opération asynchrone. Utilisezawaitpour vous assurer que l'opération de copie est terminée avant d'accéder aux données de pixels. - Restrictions de sécurité : Soyez conscient des restrictions de sécurité qui peuvent s'appliquer lors de l'accès aux données de pixels de vidéos d'origine croisée (cross-origin).
Exemple : Conversion YUV vers RGB
Considérons un exemple plus complexe : la conversion d'un VideoFrame YUV420 en un VideoFrame RGB. Cela implique de lire les plans Y, U et V, de les convertir en valeurs RGB, puis de créer un nouveau VideoFrame RGB.
Cette conversion peut être implémentée en utilisant la formule suivante :
R = Y + 1.402 * (Cr - 128)
G = Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128)
B = Y + 1.772 * (Cb - 128)
Voici le code :
async function convertYUV420ToRGBA(videoFrame) {
const width = videoFrame.codedWidth;
const height = videoFrame.codedHeight;
const yPlaneSize = width * height;
const uvPlaneSize = width * height / 4;
const yuvBuffer = new ArrayBuffer(yPlaneSize + 2 * uvPlaneSize);
const yuvPlanes = new Uint8ClampedArray(yuvBuffer);
const layout = [
{ offset: 0, stride: width }, // Plan Y
{ offset: yPlaneSize, stride: width / 2 }, // Plan U
{ offset: yPlaneSize + uvPlaneSize, stride: width / 2 } // Plan V
];
await videoFrame.copyTo(yuvPlanes, {
format: 'I420',
codedWidth: width,
codedHeight: height,
layout: layout
});
const rgbaBuffer = new ArrayBuffer(width * height * 4);
const rgba = new Uint8ClampedArray(rgbaBuffer);
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const yIndex = y * width + x;
const uIndex = Math.floor(y / 2) * (width / 2) + Math.floor(x / 2) + yPlaneSize;
const vIndex = Math.floor(y / 2) * (width / 2) + Math.floor(x / 2) + yPlaneSize + uvPlaneSize;
const Y = yuvPlanes[yIndex];
const U = yuvPlanes[uIndex] - 128;
const V = yuvPlanes[vIndex] - 128;
let R = Y + 1.402 * V;
let G = Y - 0.34414 * U - 0.71414 * V;
let B = Y + 1.772 * U;
R = Math.max(0, Math.min(255, R));
G = Math.max(0, Math.min(255, G));
B = Math.max(0, Math.min(255, B));
const rgbaIndex = y * width * 4 + x * 4;
rgba[rgbaIndex] = R;
rgba[rgbaIndex + 1] = G;
rgba[rgbaIndex + 2] = B;
rgba[rgbaIndex + 3] = 255; // Alpha
}
}
const newFrame = new VideoFrame(rgba, {
format: 'RGBA',
codedWidth: width,
codedHeight: height,
timestamp: videoFrame.timestamp,
duration: videoFrame.duration
});
videoFrame.close(); // Libérer la trame originale
return newFrame;
}
Cet exemple démontre la puissance et la complexité du travail avec les plans VideoFrame. Il nécessite une bonne compréhension des formats de pixels, de l'organisation en mémoire et des conversions d'espaces colorimétriques.
Conclusion
L'API des plans VideoFrame de WebCodecs débloque un nouveau niveau de contrôle sur le traitement vidéo dans le navigateur. En comprenant comment accéder et manipuler directement les données de pixels, vous pouvez créer des applications avancées pour les effets vidéo en temps réel, la vision par ordinateur, le montage vidéo, et plus encore. Bien que travailler avec les plans VideoFrame puisse être difficile, les récompenses potentielles sont significatives. À mesure que WebCodecs continue d'évoluer, il deviendra sans aucun doute un outil essentiel pour les développeurs web travaillant avec les médias.
Nous vous encourageons à expérimenter avec l'API des plans VideoFrame et à explorer ses capacités. En comprenant les principes sous-jacents et en appliquant les meilleures pratiques, vous pouvez créer des applications vidéo innovantes et performantes qui repoussent les limites de ce qui est possible dans le navigateur.
Pour en savoir plus
- MDN Web Docs sur WebCodecs
- Spécification WebCodecs
- Dépôts d'exemples de code WebCodecs sur GitHub.